/*
 * Cute4jWin32.cpp  0.4.0 / Nov 5, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
#include "Cute4jWin32.h"

// Cute4jWin32 :: Includes. ----------------------------------------------------

#include <QtGui>

#ifdef CUTE4J_DEBUG
  #ifdef Q_CC_MSVC
    #include <string.h>
    #include <crtdbg.h>
    #define MSVC_DEBUG
  #endif // Q_CC_MSVC
#endif // CUTE4J_DEBUG

// Cute4jWin32 :: Definitions and Variables. -----------------------------------

typedef bool (WINAPI *FpIsThemeActive)();
typedef HANDLE (WINAPI *FpCreateActCtx)(PCACTCTX pActCtx);
typedef BOOL (WINAPI *FpActivateActCtx)(HANDLE hActCtx, ULONG_PTR *lpCookie);
typedef BOOL (WINAPI *FpDeactivateActCtx)(DWORD dwFlags, ULONG_PTR ulCookie);
typedef VOID (WINAPI *FpReleaseActCtx)(HANDLE hActCtx);

static HINSTANCE s_hInstance = 0;
static bool s_initialized = false;
static bool s_themeAvailable = false;
static bool s_themeEnabled = false;
static HANDLE hActCtx = INVALID_HANDLE_VALUE;
static ULONG_PTR ulpActivationCookie;

static FpIsThemeActive IsThemeActive = 0;
static FpCreateActCtx CreateActContext = 0;
static FpActivateActCtx ActivateActContext = 0;
static FpDeactivateActCtx DeactivateActContext = 0;
static FpReleaseActCtx ReleaseActContext = 0;

// Cute4jWin32 :: Platform-Dependent Code. -------------------------------------

BEGIN_NAMESPACE_CUTE4J_PLATFORM

void ErrorMessage(const char *title, const char *message)
{
  #ifdef MSVC_DEBUG
    char buffer[4 * 1024];
    strcpy_s(buffer, message);
    strcat_s(buffer, "\n\n Debug error?\0");
    if (MessageBoxA(0, buffer, title, MB_YESNO | MB_ICONSTOP | MB_APPLMODAL) ==
        6) {
      _CrtDbgBreak();
    }
  #else
    MessageBoxA(0, message, title, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
  #endif // MSVC_DEBUG
}

void WarningMessage(const char *title, const char *message)
{
  #ifdef MSVC_DEBUG
    char buffer[4 * 1024];
    strcpy_s(buffer, message);
    strcat_s(buffer, "\n\n Debug warning?\0");
    if (MessageBoxA(0, buffer, title, MB_YESNO | MB_ICONWARNING |
        MB_APPLMODAL) == 6) {
      _CrtDbgBreak();
    }
  #else
    MessageBoxA(0, message, title, MB_OK | MB_ICONWARNING | MB_APPLMODAL);
  #endif // MSVC_DEBUG
}

void InformationMessage(const char *title, const char *message)
{
  MessageBoxA(0, message, title, MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
}

END_NAMESPACE_CUTE4J_PLATFORM

// Cute4jWin32 :: Win32 Code. --------------------------------------------------

BEGIN_NAMESPACE_CUTE4J_PLATFORM_WIN32

/*!
 * \brief Initializes the library.
 */
void initialize()
{
  if (!s_initialized) {
    s_initialized = true;
    if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP) {
      QLibrary themeLib("uxtheme");
      themeLib.load();
      if (themeLib.isLoaded()) {
        IsThemeActive = (FpIsThemeActive)themeLib.resolve("IsAppThemed");
        if (IsThemeActive) {
          s_themeAvailable = IsThemeActive();
        }
        themeLib.unload();
      }
      if (IsThemeActive) {
        // Win98 does not support ActivateActCtx & co.
        QLibrary kernelLib("kernel32");
        kernelLib.load();
        if (kernelLib.isLoaded()) {
          CreateActContext = (FpCreateActCtx)kernelLib.resolve("CreateActCtxW");
          ActivateActContext =
                          (FpActivateActCtx)kernelLib.resolve("ActivateActCtx");
          DeactivateActContext =
                      (FpDeactivateActCtx)kernelLib.resolve("DeactivateActCtx");
          ReleaseActContext =
                            (FpReleaseActCtx)kernelLib.resolve("ReleaseActCtx");
        }
      }
    }
  }
}

/*!
 * \brief Returns HMODULE of the library.
 *
 * \return HMODULE of the library
 */
HMODULE GetLibraryHandle()
{
  return s_hInstance;
}

/*!
 * \brief Return \c true if the theme is available.
 *
 * \return \c true if the theme is available
 */
bool IsThemeAvailable()
{
  initialize();
  return s_themeAvailable;
}

/*!
 * \brief Return \c true if theming is enabled.
 *
 * \return \c true if theming is enabled
 */
bool isThemeEnabled()
{
  return s_themeEnabled;
}

/*!
 * \brief Enables theming.
 */
void EnableTheme()
{
  initialize();
  if (s_themeAvailable && !s_themeEnabled) {
    DWORD dwChars;
    TCHAR ModuleFileNameBuffer[MAX_PATH];
    LPTSTR lpsz = ModuleFileNameBuffer;
    DWORD dwModuleFileNameBufferAvailable =
                                  sizeof(ModuleFileNameBuffer) / sizeof(TCHAR);
    while (true) {
      dwChars = GetModuleFileName(s_hInstance, lpsz,
                                  dwModuleFileNameBufferAvailable);
      if (dwChars == 0) {
        return;
      }
      if (dwChars < dwModuleFileNameBufferAvailable) {
        break;
      }
      if (lpsz != ModuleFileNameBuffer) {
        delete[] lpsz;
      }
      dwModuleFileNameBufferAvailable += MAX_PATH;
      lpsz = new TCHAR[dwModuleFileNameBufferAvailable];
      if (lpsz == NULL) {
        return;
      }
    }
    ACTCTX actctx;
    int actctxSize = sizeof(actctx);
    memset(&actctx, 0, actctxSize);
    actctx.cbSize = actctxSize;
    actctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
    actctx.lpSource = lpsz;
    actctx.lpResourceName = MAKEINTRESOURCE(1);
    hActCtx = CreateActContext(&actctx);
    if (lpsz != ModuleFileNameBuffer) {
      delete []lpsz;
    }
    if (hActCtx != INVALID_HANDLE_VALUE) {
      if (ActivateActContext(hActCtx, &ulpActivationCookie)) {
        s_themeEnabled = TRUE;
      } else {
        ReleaseActContext(hActCtx);
      }
    }
  }
}

/*!
 * \brief Disables theming.
 */
void DisableTheme()
{
  if (s_themeEnabled) {
    DeactivateActContext(0, ulpActivationCookie);
    ReleaseActContext(hActCtx);
    s_themeEnabled = false;
  }
}

/*!
 * \brief Called when system theme has changed.
 */
void SystemThemeChanged()
{
  s_initialized = false;
}

END_NAMESPACE_CUTE4J_PLATFORM_WIN32

// Cute4jWin32 :: DllMain. -----------------------------------------------------

BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID)
{
  if (fdwReason == DLL_PROCESS_ATTACH) {
    if (s_hInstance == 0) {
      if (!hInstDLL) {
        return FALSE;
      }
      s_hInstance = hInstDLL;
      // NOTE: Do not use EnableTheme() from DllMain!
    }
  }
  return TRUE;
}
